#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <fstream>

using namespace std;

class Shell {
public:
    // 构造函数
    Shell() {}

    // 主运行循环，接收用户输入并执行命令
    void run() {
        string input;
        while (true) {
            cout << "Shell> "; // 打印提示符
            getline(cin, input); // 读取一行输入

            if (input == "exit") { // 检查是否输入退出命令
                break;
            }

            execute_command(input); // 执行用户输入的命令
        }
    }

private:
    // 分割字符串为令牌，使用指定的分隔符
    vector<string> split(const string &str, char delimiter) {
        vector<string> tokens;
        string token;
        istringstream tokenStream(str);

        while (getline(tokenStream, token, delimiter)) {
            tokens.push_back(token);
        }

        return tokens;
    }

    // 处理输入中的重定向符号（> 和 <）
    void handle_redirection(vector<string> &tokens) {
        for (size_t i = 0; i < tokens.size(); ++i) {
            if (tokens[i] == ">") { // 输出重定向
                if (i + 1 < tokens.size()) {
                    int fd = open(tokens[i + 1].c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644);
                    if (fd < 0) {
                        perror("open"); // 错误处理
                        exit(1);
                    }
                    if (dup2(fd, STDOUT_FILENO) < 0) {
                        perror("dup2");
                        exit(1);
                    }
                    tokens.erase(tokens.begin() + i, tokens.begin() + i + 2); // 移除处理过的重定向标记及其参数
                    close(fd);
                } else {
                    cerr << "Syntax error: no output file specified after '>'" << endl;
                    tokens.clear(); // 清空令牌，避免执行错误的命令
                    break;
                }
            } else if (tokens[i] == "<") { // 输入重定向
                if (i + 1 < tokens.size()) {
                    int fd = open(tokens[i + 1].c_str(), O_RDONLY);
                    if (fd < 0) {
                        perror("open");
                        exit(1);
                    }
                    if (dup2(fd, STDIN_FILENO) < 0) {
                        perror("dup2");
                        exit(1);
                    }
                    tokens.erase(tokens.begin() + i, tokens.begin() + i + 2);
                    close(fd);
                } else {
                    cerr << "Syntax error: no input file specified after '<'" << endl;
                    tokens.clear();
                    break;
                }
            }
        }
    }

    // 执行命令
    void execute_command(const string &input) {
        vector<string> tokens = split(input, ' ');
        handle_redirection(tokens);

        if (tokens.empty()) {
            return;
        }

        if (tokens[0] == "script") { // 特殊命令：执行脚本文件
            if (tokens.size() < 2) {
                cerr << "Syntax error: no script file specified" << endl;
                return;
            }
            execute_script(tokens[1]);
            return;
        }

        vector<char *> args(tokens.size() + 1);
        for (size_t i = 0; i < tokens.size(); ++i) {
            args[i] = const_cast<char *>(tokens[i].c_str());
        }
        args[tokens.size()] = nullptr;

        pid_t pid = fork();
        if (pid == 0) { // 子进程执行命令
            execvp(args[0], args.data());
            perror("execvp"); // 错误处理
            exit(1);
        } else if (pid > 0) { // 父进程等待子进程结束
            int status;
            waitpid(pid, &status, 0);
        } else {
            perror("fork");
            exit(1);
        }
    }

    // 执行脚本文件中的命令
    void execute_script(const string &filename) {
        ifstream script_file(filename);
        if (!script_file.is_open()) {
            cerr << "Error: unable to open script file " << filename << endl;
            return;
        }

        string line;
        while (getline(script_file, line)) {
            vector<string> tokens = split(line, ' ');
            handle_redirection(tokens);
            execute_command(line);
        }

        script_file.close();
    }
};

// 主函数，创建Shell对象并启动运行
int main() {
    Shell shell;
    shell.run();
    return 0;
}

